package name.luoyong.shiro.shiroIniCustom.realm;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

public class MyRealm extends AuthorizingRealm {
	
	private Cache<String,List<String>> rolePermissionsCache;
	private String rolePermissionsCacheName="rolePermissionsCache";
	
	@Autowired
	private JdbcTemplate jdbcTemplate;


	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String username = (String) token.getPrincipal();
		
		if(username == null) {
			throw new AccountException("Error : username is null");
		}
		
		String password;
		try {
			password = jdbcTemplate.queryForObject(
				"select password from users where username=?",
				new Object[]{username},
				String.class);
		} catch(EmptyResultDataAccessException e) {
			throw new UnknownAccountException();
		}
		
		AuthenticationInfo info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName());
		
		return info;
	}
	
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String username = (String) principals.getPrimaryPrincipal();
		
		// get roles
		List<String> roles = jdbcTemplate.queryForList(
										"select role_name  from user_roles where username=?",
										new Object[]{username},
										String.class);
		
		// get permisstions
		Set<String> permissions = new HashSet<String>();
		for(String role : roles) {
			permissions.addAll(getPermissionsForRole(role));
		}
		
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.addRoles(roles);
		info.addStringPermissions(permissions);
		return info;
	}
	
	private List<String> getPermissionsForRole(String roleName) {
		if(rolePermissionsCache == null) {
			rolePermissionsCache = getCacheManager().getCache(rolePermissionsCacheName);
		}
		
		List<String> permissions = rolePermissionsCache.get(roleName);
		
		if(permissions == null) {
			permissions = jdbcTemplate.queryForList("select permission from roles_permissions where role_name=?",
											new Object[]{roleName},
											String.class);
			rolePermissionsCache.put(roleName, permissions);
		}
		
		return permissions;
	}

}
